"""
视频服务层
提供视频处理相关的业务逻辑
"""

import os
import logging
import json
import uuid
import subprocess
from typing import Dict, Any
from PIL import Image, ImageDraw
from app.tools.video_tools import VideoTools
from app.tools.utils import get_file_size_mb

class VideoService:
    """视频服务类"""
    
    def __init__(self, upload_folder: str, output_folder: str):
        """
        初始化视频服务
        
        Args:
            upload_folder: 上传文件夹路径
            output_folder: 输出文件夹路径
        """
        self.upload_folder = upload_folder
        self.output_folder = output_folder
        self.video_tools = VideoTools()
    
    def convert_format_service(self, video_path: str, target_format: str) -> Dict[str, Any]:
        """
        格式转换服务
        
        Args:
            video_path: 视频文件路径
            target_format: 目标格式
            
        Returns:
            处理结果字典
        """
        try:
            # 获取原始文件信息
            original_size = get_file_size_mb(video_path)
            
            # 转换格式
            output_path = self.video_tools.convert_format(video_path, target_format, self.output_folder)
            
            # 获取输出文件信息
            output_size = get_file_size_mb(output_path)
            
            return {
                'success': True,
                'output_path': output_path,
                'original_size_mb': original_size,
                'output_size_mb': output_size,
                'target_format': target_format,
                'message': '格式转换成功'
            }
        except Exception as e:
            logging.error(f"格式转换失败: {e}")
            return {
                'success': False,
                'error': str(e),
                'message': '格式转换失败'
            }
    
    def compress_video_service(self, video_path: str, quality: str = 'medium') -> Dict[str, Any]:
        """
        视频压缩服务
        
        Args:
            video_path: 视频文件路径
            quality: 压缩质量
            
        Returns:
            处理结果字典
        """
        try:
            # 获取原始文件信息
            original_size = get_file_size_mb(video_path)
            
            # 压缩视频
            output_path = self.video_tools.compress_video(video_path, self.output_folder, quality)
            
            # 获取输出文件信息
            output_size = get_file_size_mb(output_path)
            
            # 计算压缩率
            compression_ratio = ((original_size - output_size) / original_size) * 100
            
            return {
                'success': True,
                'output_path': output_path,
                'original_size_mb': original_size,
                'output_size_mb': output_size,
                'compression_ratio_percent': round(compression_ratio, 2),
                'quality': quality,
                'message': '视频压缩成功'
            }
        except Exception as e:
            logging.error(f"视频压缩失败: {e}")
            return {
                'success': False,
                'error': str(e),
                'message': '视频压缩失败'
            }
    
    def get_video_info_service(self, video_path: str) -> Dict[str, Any]:
        """
        获取视频信息服务
        
        Args:
            video_path: 视频文件路径
            
        Returns:
            视频信息字典
        """
        try:
            # 获取视频信息
            info = self.video_tools.get_video_info(video_path)
            
            # 添加文件大小信息
            info['file_size_mb'] = get_file_size_mb(video_path)
            
            return {
                'success': True,
                'video_info': info,
                'message': '视频信息获取成功'
            }
        except Exception as e:
            logging.error(f"视频信息获取失败: {e}")
            return {
                'success': False,
                'error': str(e),
                'message': '视频信息获取失败'
            }
    
    def apply_mask_service(self, video_path: str, mask_info: Dict[str, Any], 
                          is_preview: bool = False, start_time: float = 0, 
                          duration: float = None) -> Dict[str, Any]:
        """
        应用遮挡到视频服务
        
        Args:
            video_path: 视频文件路径
            mask_info: 遮挡信息字典
            is_preview: 是否为预览模式
            start_time: 开始时间（秒）
            duration: 持续时间（秒），None表示处理整个视频
            
        Returns:
            处理结果字典
        """
        try:
            # 获取原始文件信息
            original_size = get_file_size_mb(video_path)
            
            # 生成遮挡后的视频
            output_path = self._apply_mask_to_video(video_path, mask_info, is_preview, start_time, duration)
            
            # 获取输出文件信息
            output_size = get_file_size_mb(output_path)
            
            return {
                'success': True,
                'output_path': output_path,
                'original_size_mb': original_size,
                'output_size_mb': output_size,
                'mask_count': len(mask_info.get('masks', [])),
                'is_preview': is_preview,
                'start_time': start_time if is_preview else None,
                'duration': duration if is_preview else None,
                'message': '遮挡应用成功'
            }
        except Exception as e:
            logging.error(f"遮挡应用失败: {e}")
            return {
                'success': False,
                'error': str(e),
                'message': '遮挡应用失败'
            }
    
    def _apply_mask_to_video(self, video_path: str, mask_info: Dict[str, Any], 
                            is_preview: bool = False, start_time: float = 0, 
                            duration: float = None) -> str:
        """
        应用遮挡到视频
        
        Args:
            video_path: 视频文件路径
            mask_info: 遮挡信息字典
            is_preview: 是否为预览模式
            start_time: 开始时间（秒）
            duration: 持续时间（秒），None表示处理整个视频
            
        Returns:
            输出视频路径
        """
        try:
            # 生成唯一的输出文件名
            output_filename = f"masked_{uuid.uuid4().hex[:8]}.mp4"
            output_path = os.path.join(self.output_folder, output_filename)
            
            # 确保输出目录存在
            os.makedirs(self.output_folder, exist_ok=True)
            
            # 获取画布尺寸
            canvas_width = mask_info.get('canvas', {}).get('width', 1920)
            canvas_height = mask_info.get('canvas', {}).get('height', 1080)
            
            # 创建遮挡图像
            mask_image_path = self._create_mask_image(mask_info, canvas_width, canvas_height)
            
            try:
                # 使用FFmpeg应用遮挡
                self._apply_mask_with_ffmpeg(video_path, mask_image_path, output_path, 
                                           is_preview, start_time, duration)
                
                # 检查输出文件是否生成
                if os.path.exists(output_path):
                    logging.info(f"输出文件已生成: {output_path}")
                    logging.info(f"输出文件大小: {os.path.getsize(output_path)} 字节")
                else:
                    logging.error(f"输出文件未生成: {output_path}")
                
                # 清理临时遮挡图像
                if os.path.exists(mask_image_path):
                    os.remove(mask_image_path)
                
                return output_path
                
            except Exception as e:
                # 清理临时文件
                if os.path.exists(mask_image_path):
                    os.remove(mask_image_path)
                raise e
                
        except Exception as e:
            logging.error(f"遮挡应用失败: {e}")
            raise e
    
    def _create_mask_image(self, mask_info: Dict[str, Any], width: int, height: int) -> str:
        """
        创建遮挡图像
        
        Args:
            mask_info: 遮挡信息
            width: 图像宽度
            height: 图像高度
            
        Returns:
            遮挡图像路径
        """
        try:
            # 创建透明背景图像
            mask_img = Image.new('RGBA', (width, height), (0, 0, 0, 0))
            draw = ImageDraw.Draw(mask_img)
            
            masks = mask_info.get('masks', [])
            logging.info(f"处理遮挡区块数量: {len(masks)}")
            
            for i, mask in enumerate(masks):
                mask_type = mask.get('type', 'rectangle')
                color = mask.get('color', '#ff4757')
                opacity = mask.get('opacity', 50)
                
                logging.info(f"处理遮挡区块 {i+1}: 类型={mask_type}, 颜色={color}, 透明度={opacity}")
                
                # 转换颜色格式
                if color.startswith('#'):
                    r = int(color[1:3], 16)
                    g = int(color[3:5], 16)
                    b = int(color[5:7], 16)
                else:
                    r, g, b = 255, 71, 87  # 默认红色
                
                # 计算透明度
                alpha = int((opacity / 100) * 255)
                
                if mask_type == 'rectangle':
                    x = int(mask.get('x', 0))
                    y = int(mask.get('y', 0))
                    w = int(mask.get('width', 100))
                    h = int(mask.get('height', 100))
                    
                    logging.info(f"绘制矩形: x={x}, y={y}, w={w}, h={h}")
                    draw.rectangle([x, y, x + w, y + h], fill=(r, g, b, alpha))
                    
                elif mask_type == 'circle':
                    x = int(mask.get('x', 0))
                    y = int(mask.get('y', 0))
                    w = int(mask.get('width', 100))
                    h = int(mask.get('height', 100))
                    radius = min(w, h) // 2
                    center_x = x + w // 2
                    center_y = y + h // 2
                    
                    logging.info(f"绘制圆形: 中心=({center_x}, {center_y}), 半径={radius}")
                    draw.ellipse([center_x - radius, center_y - radius, 
                                center_x + radius, center_y + radius], 
                               fill=(r, g, b, alpha))
                    
                elif mask_type == 'ellipse':
                    x = int(mask.get('x', 0))
                    y = int(mask.get('y', 0))
                    w = int(mask.get('width', 100))
                    h = int(mask.get('height', 100))
                    
                    logging.info(f"绘制椭圆: x={x}, y={y}, w={w}, h={h}")
                    draw.ellipse([x, y, x + w, y + h], fill=(r, g, b, alpha))
                    
                elif mask_type == 'polygon':
                    points = mask.get('points', [])
                    if len(points) >= 3:
                        point_list = [(int(p.get('x', 0)), int(p.get('y', 0))) for p in points]
                        logging.info(f"绘制多边形: 点数={len(point_list)}")
                        draw.polygon(point_list, fill=(r, g, b, alpha))
                    else:
                        logging.warning(f"多边形点数不足: {len(points)}")
            
            # 保存遮挡图像
            mask_filename = f"mask_{uuid.uuid4().hex[:8]}.png"
            mask_path = os.path.join(self.output_folder, mask_filename)
            mask_img.save(mask_path, 'PNG')
            
            logging.info(f"遮挡图像已保存: {mask_path}")
            return mask_path
            
        except Exception as e:
            logging.error(f"创建遮挡图像失败: {e}")
            raise e
    
    def _apply_mask_with_ffmpeg(self, video_path: str, mask_image_path: str, output_path: str,
                               is_preview: bool = False, start_time: float = 0, 
                               duration: float = None):
        """
        使用FFmpeg应用遮挡
        
        Args:
            video_path: 视频文件路径
            mask_image_path: 遮挡图像路径
            output_path: 输出视频路径
            is_preview: 是否为预览模式
            start_time: 开始时间（秒）
            duration: 持续时间（秒），None表示处理整个视频
        """
        try:
            # 构建FFmpeg命令
            ffmpeg_cmd = ['ffmpeg']
            
            # 如果是预览模式或指定了时间范围，添加时间参数
            if is_preview or duration is not None:
                ffmpeg_cmd.extend(['-ss', str(start_time)])  # 开始时间
                if duration is not None:
                    ffmpeg_cmd.extend(['-t', str(duration)])  # 持续时间
            
            ffmpeg_cmd.extend([
                '-i', video_path,           # 输入视频
                '-i', mask_image_path,      # 遮挡图像
                '-filter_complex',
                '[0][1]overlay=0:0',        # 叠加遮挡
                '-c:a', 'copy',             # 复制音频
                '-y',                        # 覆盖输出文件
                output_path
            ])
            
            # 执行FFmpeg命令
            result = subprocess.run(ffmpeg_cmd, capture_output=True, text=True)
            
            if result.returncode != 0:
                logging.error(f"FFmpeg执行失败: {result.stderr}")
                raise Exception(f"FFmpeg处理失败: {result.stderr}")
            
            # 检查输出文件是否存在
            if not os.path.exists(output_path):
                raise Exception("输出文件未生成")
            
            logging.info(f"FFmpeg处理成功: {output_path}")
            
        except Exception as e:
            logging.error(f"FFmpeg遮挡应用失败: {e}")
            raise e 
    
    def add_background_music_service(self, video_path: str, music_path: str, 
                                   volume_ratio: float = 0.3, loop_music: bool = True) -> Dict[str, Any]:
        """
        为视频添加背景音乐服务
        
        Args:
            video_path: 视频文件路径
            music_path: 背景音乐文件路径
            volume_ratio: 背景音乐音量比例，0.0-1.0，默认0.3
            loop_music: 是否循环播放背景音乐，默认True
            
        Returns:
            处理结果字典
        """
        try:
            # 获取原始文件信息
            original_size = get_file_size_mb(video_path)
            
            # 添加背景音乐
            output_path = self.video_tools.add_background_music(
                video_path, music_path, self.output_folder, volume_ratio, loop_music
            )
            
            # 获取输出文件信息
            output_size = get_file_size_mb(output_path)
            
            return {
                'success': True,
                'output_path': output_path,
                'original_size_mb': original_size,
                'output_size_mb': output_size,
                'volume_ratio': volume_ratio,
                'loop_music': loop_music,
                'message': '背景音乐添加成功'
            }
        except Exception as e:
            logging.error(f"添加背景音乐失败: {e}")
            return {
                'success': False,
                'error': str(e),
                'message': '添加背景音乐失败'
            }
    
    def add_background_music_with_options_service(self, video_path: str, music_path: str,
                                                volume_ratio: float = 0.3, loop_music: bool = True,
                                                fade_in_duration: float = 0, fade_out_duration: float = 0,
                                                start_time: float = 0, end_time: float = None) -> Dict[str, Any]:
        """
        为视频添加背景音乐服务（带更多选项）
        
        Args:
            video_path: 视频文件路径
            music_path: 背景音乐文件路径
            volume_ratio: 背景音乐音量比例，0.0-1.0，默认0.3
            loop_music: 是否循环播放背景音乐，默认True
            fade_in_duration: 淡入时长（秒），默认0
            fade_out_duration: 淡出时长（秒），默认0
            start_time: 音乐开始时间（秒），默认0
            end_time: 音乐结束时间（秒），默认None（使用完整音乐）
            
        Returns:
            处理结果字典
        """
        try:
            # 获取原始文件信息
            original_size = get_file_size_mb(video_path)
            
            # 添加背景音乐
            output_path = self.video_tools.add_background_music_with_options(
                video_path, music_path, self.output_folder, volume_ratio, loop_music,
                fade_in_duration, fade_out_duration, start_time, end_time
            )
            
            # 获取输出文件信息
            output_size = get_file_size_mb(output_path)
            
            return {
                'success': True,
                'output_path': output_path,
                'original_size_mb': original_size,
                'output_size_mb': output_size,
                'volume_ratio': volume_ratio,
                'loop_music': loop_music,
                'fade_in_duration': fade_in_duration,
                'fade_out_duration': fade_out_duration,
                'start_time': start_time,
                'end_time': end_time,
                'message': '背景音乐添加成功'
            }
        except Exception as e:
            logging.error(f"添加背景音乐失败: {e}")
            return {
                'success': False,
                'error': str(e),
                'message': '添加背景音乐失败'
            } 
    
    def merge_video_audio_service(self, video_path: str, audio_path: str, 
                                merge_type: str = 'mix', original_volume: float = 1.0, 
                                new_audio_volume: float = 1.0, fade_in_duration: float = 0, 
                                fade_out_duration: float = 0, preview_duration: int = None) -> Dict[str, Any]:
        """
        视频音频合并服务
        
        Args:
            video_path: 视频文件路径
            audio_path: 音频文件路径
            merge_type: 合并类型，'mix'为混合音频，'replace'为替换原音频
            original_volume: 原音频音量，0.0-2.0，默认1.0
            new_audio_volume: 新音频音量，0.0-2.0，默认1.0
            fade_in_duration: 淡入时长（秒），默认0
            fade_out_duration: 淡出时长（秒），默认0
            preview_duration: 预览时长（秒），None表示生成完整视频
            
        Returns:
            处理结果字典
        """
        try:
            # 获取原始文件信息
            original_size = get_file_size_mb(video_path)
            
            # 合并视频和音频
            output_path = self.video_tools.merge_video_audio(
                video_path, audio_path, self.output_folder, merge_type,
                original_volume, new_audio_volume, fade_in_duration, fade_out_duration,
                preview_duration=preview_duration
            )
            
            # 获取输出文件信息
            output_size = get_file_size_mb(output_path)
            
            return {
                'success': True,
                'output_path': output_path,
                'original_size_mb': original_size,
                'output_size_mb': output_size,
                'merge_type': merge_type,
                'original_volume': original_volume,
                'new_audio_volume': new_audio_volume,
                'fade_in_duration': fade_in_duration,
                'fade_out_duration': fade_out_duration,
                'preview_duration': preview_duration,
                'message': '视频音频合并成功'
            }
        except Exception as e:
            logging.error(f"视频音频合并失败: {e}")
            return {
                'success': False,
                'error': str(e),
                'message': '视频音频合并失败'
            } 